/*
   Copyright (c) 2023 李伟国
   learner-platform is licensed under Mulan PSL v2.
   You can use this software according to the terms and conditions of the Mulan PSL v2. 
   You may obtain a copy of Mulan PSL v2 at:
               http://license.coscl.org.cn/MulanPSL2 
   THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.  
   See the Mulan PSL v2 for more details. 
*/

package cn.platform.handler;

import cn.platform.response.ErrorResponseData;
import cn.platform.response.ResponseData;
import org.apache.shiro.ShiroException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletResponse;

@RestControllerAdvice
public class GlobalExceptionHandler {
    // 捕捉shiro的异常
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ExceptionHandler(ShiroException.class)
    public ResponseData handle401(ShiroException e, HttpServletResponse httpServletResponse){
        setHttpOrigin(httpServletResponse);
        e.printStackTrace();
        return new ErrorResponseData(ResponseData.DEFAULT_NO_LOGIN_CODE,ResponseData.DEFAULT_NO_LOGIN,e.getMessage());
    }
    // 捕捉未登录的异常
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ExceptionHandler(UnauthenticatedException.class)
    public ResponseData handle401(UnauthenticatedException e, HttpServletResponse httpServletResponse) {
        setHttpOrigin(httpServletResponse);
        e.printStackTrace();
        return new ErrorResponseData(ResponseData.DEFAULT_NO_LOGIN_CODE,ResponseData.DEFAULT_NO_LOGIN,e.getMessage());
    }

    // 捕捉没有相应的权限或者角色的异常
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ExceptionHandler(UnauthorizedException.class)
    public ResponseData handle401(UnauthorizedException e, HttpServletResponse httpServletResponse) {
        setHttpOrigin(httpServletResponse);
        e.printStackTrace();
        return new ErrorResponseData(ResponseData.DEFAULT_NO_PERMISSION_CODE,ResponseData.DEFAULT_NO_PERMISSION,e.getMessage());
    }

    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ExceptionHandler(AuthenticationException.class)
    public ResponseData handle401(AuthenticationException e, HttpServletResponse httpServletResponse) {
        setHttpOrigin(httpServletResponse);
        e.printStackTrace();
        return new ErrorResponseData(ResponseData.DEFAULT_NO_LOGIN_CODE,e.getMessage(),e.getMessage());
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Exception.class)
    public ResponseData handle500(Exception e, HttpServletResponse httpServletResponse){
        String[] split = e.getMessage().split(": ");
        //Filter中的报错转给Controller后的Exception不能转换成AuthenticationException, 所以就直接看一看报错里有没有
        if(split[0].equals("org.apache.shiro.authc.AuthenticationException")){
            return new ErrorResponseData(ResponseData.DEFAULT_NO_LOGIN_CODE,ResponseData.DEFAULT_NO_LOGIN,split[1]);
        }
        else if(split[0].equals("TokenExpiredException")){
            return new ErrorResponseData(ResponseData.DEFAULT_NO_LOGIN_CODE,"登录过期，请重新登录",split[1]);
        }
        setHttpOrigin(httpServletResponse);
        e.printStackTrace();
        if(split.length>1){
            return new ErrorResponseData(500,split[split.length-1],"服务器异常");
        }
        return new ErrorResponseData(500,"服务器异常");
    }

    @ResponseStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE)
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResponseData handle416(){
        return new ErrorResponseData(416, "请求参数缺失");
    }

    // 解决跨域问题
    private static void setHttpOrigin(HttpServletResponse httpServletResponse){
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "*");
        httpServletResponse.setHeader("Access-Control-Allow-Origin","*");
        httpServletResponse.setHeader("Access-Control-Allow-Headers", "*");
        httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
    }
}
